#include "StdAfx.h"
#include "Arc.h"
#include "ZCmnFile.h"
#include <DbgHelp.h>
#include <atlconv.h>
#include <algorithm>
#include "process.h"
#include <cstdlib>
#include "GlobalDefs.h"
#pragma comment(lib,"DbgHelp")
#pragma comment(lib,"atlsd")
#include <string>
using std::wstring;

int Decompress(unsigned char * compressed, unsigned int compressed_size, unsigned char * decompressed, unsigned int * decompressed_size )
{
	unsigned int est_size = *decompressed_size * 5;
	if( est_size < 4096 ) est_size = 4096;
	unsigned char * workspace = (unsigned char *)malloc( est_size );
	int result = Z_OK;
	do 
	{
		result = uncompress((Bytef*)workspace, (uLongf *)&est_size, (Bytef*)compressed, compressed_size);
		if( result == Z_OK )
		{
			if( *decompressed_size >= est_size )
			{
				*decompressed_size = est_size;
				memcpy( decompressed, workspace, est_size );
			}
			else
			{
				result = -10; // decompression size mismatch
			}
		}
		else if( result == Z_BUF_ERROR )
		{
			est_size *= 2;
			workspace = (unsigned char *)realloc(workspace, est_size);
		}
	} while( result == Z_BUF_ERROR );
	free( workspace );
	return result;
}

int Compress(unsigned char * decompressed, unsigned int decompressed_size, unsigned char * compressed, unsigned int * compressed_size )
{
	unsigned int est_size = decompressed_size * 5;
	if( est_size < 4096 ) est_size = 4096;
	unsigned char * workspace = (unsigned char *)malloc( est_size );
	int result = Z_OK;
	do 
	{
		result = compress((Bytef*)workspace, (uLongf *)&est_size, (Bytef*)decompressed, decompressed_size);
		if( result == Z_OK )
		{
			*compressed_size = est_size;
			memcpy( compressed, workspace, est_size );
		}
		else if( result == Z_BUF_ERROR )
		{
			est_size *= 2;
			workspace = (unsigned char *)realloc(workspace, est_size);
		}
	} while( result == Z_BUF_ERROR );
	free( workspace );
	return result;
}

BYTE DecryptTable[] =
{
	0x30, 0x22, 0x41, 0xA8, 0x5B, 0xA6, 0x6A, 0x49, 0xBF, 0x53, 0x35, 0xE5, 0x9E, 0x0E, 0xEC, 0xB8, 0x5E, 0x15, 0x1F, 0xC1, 0x4F, 0xEC, 0x77, 0xE8, 0xB7, 0x4E, 0x87, 0xE6, 0xF5, 0x3C, 0xB3, 0x43
	, 0xCC, 0x53, 0x36, 0xAC, 0x5A, 0x77, 0xB8, 0xDD, 0x30, 0x74, 0x8C, 0x4A, 0x9A, 0x9B, 0xBC, 0x0A, 0xA4, 0xAD, 0xBB, 0x13, 0x4B, 0x8C, 0xD4, 0x80, 0xCE, 0x65, 0x1D, 0x08, 0x5A, 0x6A, 0x6F, 0x25
	, 0xF9, 0x3F, 0xEF, 0x1B, 0xA4, 0x72, 0x14, 0xED, 0x97, 0x22, 0x4A, 0x2E, 0xB8, 0x96, 0x4B, 0x8E, 0x96, 0x93, 0xF1, 0x28, 0xB2, 0x0B, 0x3C, 0xF8, 0x5D, 0xAA, 0xA9, 0x82, 0x13, 0x6E, 0xC1, 0xA9
	, 0x20, 0x57, 0xB2, 0x5B, 0x16, 0xCF, 0x9E, 0x5F, 0xD4, 0xCC, 0x2E, 0xF5, 0xC9, 0x4C, 0x1C, 0xEE, 0xE3, 0x3F, 0x29, 0xB3, 0x06, 0x70, 0x43, 0x3D, 0xF5, 0x90, 0xA2, 0x42, 0x02, 0x98, 0x50, 0xFD
	, 0x5D, 0x4E, 0x92, 0xAD, 0xAD, 0x7F, 0xAB, 0x60, 0x2C, 0xB8, 0x43, 0x76, 0x8F, 0x5F, 0xE6, 0xA7, 0x19, 0xE0, 0xB9, 0xB5, 0x62, 0x6B, 0xD4, 0x47, 0x69, 0x34, 0x0E, 0x6D, 0xA4, 0x52, 0xE3, 0x64
	, 0x4A, 0x65, 0x47, 0xF5, 0x3F, 0x53, 0x5E, 0x8B, 0x1B, 0xFD, 0x21, 0xF7, 0xBA, 0x68, 0xF9, 0xDF, 0x68, 0xA8, 0x96, 0x0F, 0x8B, 0x01, 0x97, 0x58, 0x8C, 0x1E, 0xEF, 0xB3, 0x41, 0x44, 0x21, 0xDA
	, 0xE0, 0xF4, 0xE0, 0x2D, 0xCD, 0x0B, 0xF0, 0x5C, 0x59, 0xD6, 0x99, 0xE7, 0x01, 0x15, 0x67, 0x32, 0xE0, 0x12, 0x2F, 0xCD, 0xA2, 0xDE, 0x52, 0xCE, 0xEC, 0xEF, 0x77, 0x0E, 0xBC, 0x38, 0x64, 0x8D
	, 0xB4, 0xDB, 0x67, 0xFF, 0xC8, 0x66, 0x0C, 0x8A, 0x60, 0xE1, 0x2E, 0x00, 0x43, 0xA9, 0x37, 0x9C, 0x11, 0xAA, 0xB9, 0x98, 0xED, 0x21, 0x35, 0xD4, 0xC3, 0xDE, 0x65, 0x54, 0x9D, 0x1C, 0xB0, 0xA9
};

BYTE HashTable[64][16] =  
{
	{0x00,0x00,0x00,0x00,0x96,0x30,0x07,0x77,0x2c,0x61,0x0e,0xee,0xba,0x51,0x09,0x99},
	{0x19,0xC4,0x6D,0x07,0x8F,0xF4,0x6A,0x70,0x35,0xA5,0x63,0xE9,0xA3,0x95,0x64,0x9E},
	{0x32,0x88,0xDB,0x0E,0xA4,0xB8,0xDC,0x79,0x1E,0xE9,0xD5,0xE0,0x88,0xD9,0xD2,0x97},
	{0x2B,0x4C,0xB6,0x09,0xBD,0x7C,0xB1,0x7E,0x07,0x2D,0xB8,0xE7,0x91,0x1D,0xBF,0x90},
	{0x64,0x10,0xB7,0x1D,0xF2,0x20,0xB0,0x6A,0x48,0x71,0xB9,0xF3,0xDE,0x41,0xBE,0x84},
	{0x7D,0xD4,0xDA,0x1A,0xEB,0xE4,0xDD,0x6D,0x51,0xB5,0xD4,0xF4,0xC7,0x85,0xD3,0x83},
	{0x56,0x98,0x6C,0x13,0xC0,0xA8,0x6B,0x64,0x7A,0xF9,0x62,0xFD,0xEC,0xC9,0x65,0x8A},
	{0x4F,0x5C,0x01,0x14,0xD9,0x6C,0x06,0x63,0x63,0x3D,0x0F,0xFA,0xF5,0x0D,0x08,0x8D},
	{0xC8,0x20,0x6E,0x3B,0x5E,0x10,0x69,0x4C,0xE4,0x41,0x60,0xD5,0x72,0x71,0x67,0xA2},
	{0xD1,0xE4,0x03,0x3C,0x47,0xD4,0x04,0x4B,0xFD,0x85,0x0D,0xD2,0x6B,0xB5,0x0A,0xA5},
	{0xFA,0xA8,0xB5,0x35,0x6C,0x98,0xB2,0x42,0xD6,0xC9,0xBB,0xDB,0x40,0xF9,0xBC,0xAC},
	{0xE3,0x6C,0xD8,0x32,0x75,0x5C,0xDF,0x45,0xCF,0x0D,0xD6,0xDC,0x59,0x3D,0xD1,0xAB},
	{0xAC,0x30,0xD9,0x26,0x3A,0x00,0xDE,0x51,0x80,0x51,0xD7,0xC8,0x16,0x61,0xD0,0xBF},
	{0xB5,0xF4,0xB4,0x21,0x23,0xC4,0xB3,0x56,0x99,0x95,0xBA,0xCF,0x0F,0xA5,0xBD,0xB8},
	{0x9E,0xB8,0x02,0x28,0x08,0x88,0x05,0x5F,0xB2,0xD9,0x0C,0xC6,0x24,0xE9,0x0B,0xB1},
	{0x87,0x7C,0x6F,0x2F,0x11,0x4C,0x68,0x58,0xAB,0x1D,0x61,0xC1,0x3D,0x2D,0x66,0xB6},
	{0x90,0x41,0xDC,0x76,0x06,0x71,0xDB,0x01,0xBC,0x20,0xD2,0x98,0x2A,0x10,0xD5,0xEF},
	{0x89,0x85,0xB1,0x71,0x1F,0xB5,0xB6,0x06,0xA5,0xE4,0xBF,0x9F,0x33,0xD4,0xB8,0xE8},
	{0xA2,0xC9,0x07,0x78,0x34,0xF9,0x00,0x0F,0x8E,0xA8,0x09,0x96,0x18,0x98,0x0E,0xE1},
	{0xBB,0x0D,0x6A,0x7F,0x2D,0x3D,0x6D,0x08,0x97,0x6C,0x64,0x91,0x01,0x5C,0x63,0xE6},
	{0xF4,0x51,0x6B,0x6B,0x62,0x61,0x6C,0x1C,0xD8,0x30,0x65,0x85,0x4E,0x00,0x62,0xF2},
	{0xED,0x95,0x06,0x6C,0x7B,0xA5,0x01,0x1B,0xC1,0xF4,0x08,0x82,0x57,0xC4,0x0F,0xF5},
	{0xC6,0xD9,0xB0,0x65,0x50,0xE9,0xB7,0x12,0xEA,0xB8,0xBE,0x8B,0x7C,0x88,0xB9,0xFC},
	{0xDF,0x1D,0xDD,0x62,0x49,0x2D,0xDA,0x15,0xF3,0x7C,0xD3,0x8C,0x65,0x4C,0xD4,0xFB},
	{0x58,0x61,0xB2,0x4D,0xCE,0x51,0xB5,0x3A,0x74,0x00,0xBC,0xA3,0xE2,0x30,0xBB,0xD4},
	{0x41,0xA5,0xDF,0x4A,0xD7,0x95,0xD8,0x3D,0x6D,0xC4,0xD1,0xA4,0xFB,0xF4,0xD6,0xD3},
	{0x6A,0xE9,0x69,0x43,0xFC,0xD9,0x6E,0x34,0x46,0x88,0x67,0xAD,0xD0,0xB8,0x60,0xDA},
	{0x73,0x2D,0x04,0x44,0xE5,0x1D,0x03,0x33,0x5F,0x4C,0x0A,0xAA,0xC9,0x7C,0x0D,0xDD},
	{0x3C,0x71,0x05,0x50,0xAA,0x41,0x02,0x27,0x10,0x10,0x0B,0xBE,0x86,0x20,0x0C,0xC9},
	{0x25,0xB5,0x68,0x57,0xB3,0x85,0x6F,0x20,0x09,0xD4,0x66,0xB9,0x9F,0xE4,0x61,0xCE},
	{0x0E,0xF9,0xDE,0x5E,0x98,0xC9,0xD9,0x29,0x22,0x98,0xD0,0xB0,0xB4,0xA8,0xD7,0xC7},
	{0x17,0x3D,0xB3,0x59,0x81,0x0D,0xB4,0x2E,0x3B,0x5C,0xBD,0xB7,0xAD,0x6C,0xBA,0xC0},
	{0x20,0x83,0xB8,0xED,0xB6,0xB3,0xBF,0x9A,0x0C,0xE2,0xB6,0x03,0x9A,0xD2,0xB1,0x74},
	{0x39,0x47,0xD5,0xEA,0xAF,0x77,0xD2,0x9D,0x15,0x26,0xDB,0x04,0x83,0x16,0xDC,0x73},
	{0x12,0x0B,0x63,0xE3,0x84,0x3B,0x64,0x94,0x3E,0x6A,0x6D,0x0D,0xA8,0x5A,0x6A,0x7A},
	{0x0B,0xCF,0x0E,0xE4,0x9D,0xFF,0x09,0x93,0x27,0xAE,0x00,0x0A,0xB1,0x9E,0x07,0x7D},
	{0x44,0x93,0x0F,0xF0,0xD2,0xA3,0x08,0x87,0x68,0xF2,0x01,0x1E,0xFE,0xC2,0x06,0x69},
	{0x5D,0x57,0x62,0xF7,0xCB,0x67,0x65,0x80,0x71,0x36,0x6C,0x19,0xE7,0x06,0x6B,0x6E},
	{0x76,0x1B,0xD4,0xFE,0xE0,0x2B,0xD3,0x89,0x5A,0x7A,0xDA,0x10,0xCC,0x4A,0xDD,0x67},
	{0x6F,0xDF,0xB9,0xF9,0xF9,0xEF,0xBE,0x8E,0x43,0xBE,0xB7,0x17,0xD5,0x8E,0xB0,0x60},
	{0xE8,0xA3,0xD6,0xD6,0x7E,0x93,0xD1,0xA1,0xC4,0xC2,0xD8,0x38,0x52,0xF2,0xDF,0x4F},
	{0xF1,0x67,0xBB,0xD1,0x67,0x57,0xBC,0xA6,0xDD,0x06,0xB5,0x3F,0x4B,0x36,0xB2,0x48},
	{0xDA,0x2B,0x0D,0xD8,0x4C,0x1B,0x0A,0xAF,0xF6,0x4A,0x03,0x36,0x60,0x7A,0x04,0x41},
	{0xC3,0xEF,0x60,0xDF,0x55,0xDF,0x67,0xA8,0xEF,0x8E,0x6E,0x31,0x79,0xBE,0x69,0x46},
	{0x8C,0xB3,0x61,0xCB,0x1A,0x83,0x66,0xBC,0xA0,0xD2,0x6F,0x25,0x36,0xE2,0x68,0x52},
	{0x95,0x77,0x0C,0xCC,0x03,0x47,0x0B,0xBB,0xB9,0x16,0x02,0x22,0x2F,0x26,0x05,0x55},
	{0xBE,0x3B,0xBA,0xC5,0x28,0x0B,0xBD,0xB2,0x92,0x5A,0xB4,0x2B,0x04,0x6A,0xB3,0x5C},
	{0xA7,0xFF,0xD7,0xC2,0x31,0xCF,0xD0,0xB5,0x8B,0x9E,0xD9,0x2C,0x1D,0xAE,0xDE,0x5B},
	{0xB0,0xC2,0x64,0x9B,0x26,0xF2,0x63,0xEC,0x9C,0xA3,0x6A,0x75,0x0A,0x93,0x6D,0x02},
	{0xA9,0x06,0x09,0x9C,0x3F,0x36,0x0E,0xEB,0x85,0x67,0x07,0x72,0x13,0x57,0x00,0x05},
	{0x82,0x4A,0xBF,0x95,0x14,0x7A,0xB8,0xE2,0xAE,0x2B,0xB1,0x7B,0x38,0x1B,0xB6,0x0C},
	{0x9B,0x8E,0xD2,0x92,0x0D,0xBE,0xD5,0xE5,0xB7,0xEF,0xDC,0x7C,0x21,0xDF,0xDB,0x0B},
	{0xD4,0xD2,0xD3,0x86,0x42,0xE2,0xD4,0xF1,0xF8,0xB3,0xDD,0x68,0x6E,0x83,0xDA,0x1F},
	{0xCD,0x16,0xBE,0x81,0x5B,0x26,0xB9,0xF6,0xE1,0x77,0xB0,0x6F,0x77,0x47,0xB7,0x18},
	{0xE6,0x5A,0x08,0x88,0x70,0x6A,0x0F,0xFF,0xCA,0x3B,0x06,0x66,0x5C,0x0B,0x01,0x11},
	{0xFF,0x9E,0x65,0x8F,0x69,0xAE,0x62,0xF8,0xD3,0xFF,0x6B,0x61,0x45,0xCF,0x6C,0x16},
	{0x78,0xE2,0x0A,0xA0,0xEE,0xD2,0x0D,0xD7,0x54,0x83,0x04,0x4E,0xC2,0xB3,0x03,0x39},
	{0x61,0x26,0x67,0xA7,0xF7,0x16,0x60,0xD0,0x4D,0x47,0x69,0x49,0xDB,0x77,0x6E,0x3E},
	{0x4A,0x6A,0xD1,0xAE,0xDC,0x5A,0xD6,0xD9,0x66,0x0B,0xDF,0x40,0xF0,0x3B,0xD8,0x37},
	{0x53,0xAE,0xBC,0xA9,0xC5,0x9E,0xBB,0xDE,0x7F,0xCF,0xB2,0x47,0xE9,0xFF,0xB5,0x30},
	{0x1C,0xF2,0xBD,0xBD,0x8A,0xC2,0xBA,0xCA,0x30,0x93,0xB3,0x53,0xA6,0xA3,0xB4,0x24},
	{0x05,0x36,0xD0,0xBA,0x93,0x06,0xD7,0xCD,0x29,0x57,0xDE,0x54,0xBF,0x67,0xD9,0x23},
	{0x2E,0x7A,0x66,0xB3,0xB8,0x4A,0x61,0xC4,0x02,0x1B,0x68,0x5D,0x94,0x2B,0x6F,0x2A},
	{0x37,0xBE,0x0B,0xB4,0xA1,0x8E,0x0C,0xC3,0x1B,0xDF,0x05,0x5A,0x8D,0xEF,0x02,0x2D}
};

BOOL g_UseNewArchPckIdxHash = FALSE;
BOOL g_NoPckIdx = FALSE;
string g_PckFileDir;
string g_ResBaseDir;
vector<FileElem> g_PckArchData[10];
map<string,FileElem> g_IdxMap;

VOID ClearPckArchData(INT _Idx = -1)
{
	if (_Idx >= 0 && _Idx < 10) {
		g_PckArchData[_Idx].clear();
	}
	else {
		for (_Idx = 0; _Idx < 10; _Idx++) {
			g_PckArchData[_Idx].clear();
		}
	}
}

void MkDir(string _FileOrDir,bool _IsFile/* = false*/)
{
	if (!_IsFile && !_FileOrDir.empty() && _FileOrDir[_FileOrDir.size()-1]!='\\') {
		_FileOrDir += "\\";
	}
	if (!PathFileExists(_FileOrDir.c_str())) {
		::MakeSureDirectoryPathExists(_FileOrDir.c_str());
	}
}

INT PckNameToIdx(const string& _PckFileName)
{
	int _Pos = -1;
	if ((_Pos = _PckFileName.rfind('\\')) != string::npos) {
		string _FileName = _PckFileName.substr(_Pos+1,_PckFileName.size() - _Pos);
		if ((_Pos = _PckFileName.rfind('.')) != string::npos) {
			_FileName = _PckFileName.substr(0,_Pos);
			return atoi(_FileName.c_str());
		}
	}
	return -1;
}

DWORD HashFileInPck(BYTE* Str, int Len)
{
	DWORD* _HashTable = (DWORD*)&HashTable;
	DWORD _Ret = -1;
	int i;
	for (i = 0; i < Len; ++i) {
		_Ret = _HashTable[(unsigned __int8)_Ret ^ *(BYTE*)(i + Str)] ^ ((unsigned int)_Ret >> 8);
	}
	return _Ret;
}

INT GetPckIdxByName(string _FileName)
{
	CA2W _WStr(_FileName.c_str());
	WCHAR* _pFileName = (WCHAR*)_WStr;
	DWORD _CheckSum = 0x1505;
	WCHAR _Char = *_pFileName;
	for (int _Idx = 0; _Char; _Char = _pFileName[_Idx]) {
		++_Idx;
		_CheckSum = _Char + 33 * _CheckSum;
	}
	if (g_UseNewArchPckIdxHash) {
		_CheckSum++;
	}
	return _CheckSum % 10;
}

INT GetRandPctPckIdx(string _FileName)
{
	INT _OrgIdx = GetPckIdxByName(_FileName);
	INT _PckIdx = rand()%10;
	if (_OrgIdx == _PckIdx) {
		_PckIdx++;
	}
	return _PckIdx%10;
}

INT GetRandPctPckIdx(INT _OrgIdx)
{
	INT _PckIdx = rand()%10;
	if (_OrgIdx == _PckIdx) {
		_PckIdx++;
	}
	return _PckIdx%10;
}

string UnZipIdexFileBuff(const string& _IdxFileName) 
{
	ZCmnFile _File;
	if (!_File.OpenFile(_IdxFileName)) {
		return "";
	}

	INT _IdxFileSize = (INT)_File.ZFileGetSize();
	string _FileBuff;
	_FileBuff.resize(_IdxFileSize,0);
	if (!_File.ReadFile((LPVOID)_FileBuff.c_str(),_IdxFileSize)) {
		return "";
	}

	BYTE* _IdxFilePtr = (BYTE*)_FileBuff.c_str();
	for (int _Idx = 0; _Idx < _IdxFileSize; ++_Idx) {
		_IdxFilePtr[_Idx] ^= DecryptTable[_Idx & 0xFF];
	}

	UINT _UnZipLen = _IdxFileSize*15;
	string _UnZipFileBuff;
	_UnZipFileBuff.resize(_UnZipLen);
	BYTE* _UnZipIdxFilePtr = (BYTE*)_UnZipFileBuff.c_str();
	INT _Err = Decompress(_IdxFilePtr,_IdxFileSize,_UnZipIdxFilePtr,&_UnZipLen);
	_UnZipFileBuff.resize(_UnZipLen);
	
	//if (_File.OpenFile(_IdxFileName+".up",true)) {
	//	_File.WriteFile((LPVOID)_UnZipFileBuff.c_str(),_UnZipLen);
	//}
	return _UnZipFileBuff;
}

BOOL ZipIdexFileBuff(const string& _IdxFileName, const string& _IdxFileBuff)
{
	ZCmnFile _File;
	if (!_File.OpenFile(_IdxFileName,true,true)) {
		return FALSE;
	}

	UINT _ZipLen = _IdxFileBuff.size()*2;
	string _ZipFileBuff;
	_ZipFileBuff.resize(_ZipLen);
	BYTE* _ZipIdxFilePtr = (BYTE*)_ZipFileBuff.c_str();
	INT _Err = Compress((BYTE*)_IdxFileBuff.c_str(),_IdxFileBuff.size(),_ZipIdxFilePtr,&_ZipLen);
	_ZipFileBuff.resize(_ZipLen);

	_ZipIdxFilePtr = (BYTE*)_ZipFileBuff.c_str();
	for (int _Idx = 0; _Idx < (int)_ZipLen; ++_Idx) {
		_ZipIdxFilePtr[_Idx] ^= DecryptTable[_Idx & 0xFF];
	}
	_File.WriteFile(_ZipIdxFilePtr,_ZipLen);
	return TRUE;
}

void MakeIdxMapByIdxBuff(const string& _IdxFileBuff,map<string,FileElem>& _IdxMap)
{
	_IdxMap.clear();
	if (_IdxFileBuff.empty()) {
		return;
	}
	BYTE* _IdxFilePtr = (BYTE*)_IdxFileBuff.c_str();
	BYTE* _UnZipBuffEnd = _IdxFilePtr + _IdxFileBuff.size();
	CHAR _FileName[MAX_PATH*2];
	while (_IdxFilePtr < _UnZipBuffEnd) {
		FileElem _Fe;
		_Fe.NameLen = *(INT16*)_IdxFilePtr;
		_IdxFilePtr+=2;
		memcpy(_FileName,_IdxFilePtr,_Fe.NameLen*2);
		*(WORD*)(_FileName+_Fe.NameLen*2) = 0;
		_Fe.Name = CW2A((LPCWSTR)&_FileName);
		_IdxFilePtr+=_Fe.NameLen*2;
		if (g_NoPckIdx) {
			trans_tolower(_Fe.Name);
			_Fe.ArchIdx = GetPckIdxByName(_Fe.Name);
		}
		else {
			_Fe.ArchIdx = *_IdxFilePtr;
		}
		_IdxFilePtr++;
		_Fe.FileLen = *(DWORD*)_IdxFilePtr;
		_IdxFilePtr+=4;
		_Fe.CRC = *(DWORD*)_IdxFilePtr;
		_IdxFilePtr+=4;
		_Fe.Offset = *(__int64*)_IdxFilePtr;
		_IdxFilePtr+=8;
		trans_tolower(_Fe.Name);
		_IdxMap[_Fe.Name] = _Fe;
	}
}

void MakeIdxBuffByIdxMap(string& _IdxFileBuff,map<string,FileElem>& _IdxMap) 
{
	map<string,FileElem>::iterator _Iter = g_IdxMap.end();
	_IdxFileBuff.clear();
	if (g_IdxMap.empty()) {
		return;
	}
	while (true) {
		--_Iter;
		FileElem& _Fe = _Iter->second;
		CA2W _WStr(_Fe.Name.c_str());
		string _IdxItem;
		_IdxItem.append((char*)&_Fe.NameLen,2);
		_IdxItem.append((char*)(WCHAR*)_WStr,_Fe.NameLen*2);
		if (g_NoPckIdx) {
			_IdxItem.append(1,(char)(GetRandPctPckIdx(_Fe.ArchIdx)));
		}
		else {
			_IdxItem.append((char*)&_Fe.ArchIdx,1);
		}
		_IdxItem.append((char*)&_Fe.FileLen,4);
		_IdxItem.append((char*)&_Fe.CRC,4);
		_IdxItem.append((char*)&_Fe.Offset,8);
		_IdxFileBuff += _IdxItem;
		if (_Iter == g_IdxMap.begin()) {
			break;
		}
	}
}

void FindAllFile(const string& _RootName,const string& _DirName,vector<string>& _FileList)
{
	WIN32_FIND_DATA _FindData;
	HANDLE hFind = INVALID_HANDLE_VALUE;
	string _FindPath = _DirName.empty()?(_RootName+"\\*.*"):(_RootName+"\\"+_DirName+"\\*.*");
	hFind = FindFirstFile(_FindPath.c_str(), &_FindData);
	if (hFind == INVALID_HANDLE_VALUE)
		return;

	string _FindFileName;
	do {
		_FindFileName = _FindData.cFileName;
		if (_FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			if (_FindFileName=="." || _FindFileName=="..") {
				continue;
			}
			else {
				string _NewDir = _DirName.empty()?_FindFileName:_DirName+"\\"+_FindFileName;
				FindAllFile(_RootName,_NewDir,_FileList);
			}
		}
		else {
			string _File = _DirName.empty()?_FindFileName:_DirName+"\\"+_FindFileName;
			if (_File != "log.txt" && _File != "PckArch.txt" && _File != "Pck.txt") {
				_FileList.push_back(_File);
			}
		}
	} while (FindNextFile(hFind, &_FindData) != 0);
	FindClose(hFind);
}

unsigned __stdcall PckArchThread(void* _pParam)
{
	INT _PckIdx = (INT)_pParam;
	if (_PckIdx >= 0 && _PckIdx < 10) {
		string _PckFile = g_PckFileDir + "\\" + string(3-AllToStr(_PckIdx).size(),'0')+AllToStr(_PckIdx)+".pck";
		vector<FileElem>& _FileList = g_PckArchData[_PckIdx];
		INT _Len = _FileList.size();
		for (INT _Idx = _Len-1; _Idx >= 0; --_Idx) {
			FileElem& _Fe = _FileList[_Idx];
			Archive(_Fe,_PckFile);
		}
	}
	return 0;
}

unsigned __stdcall UnPckArchThread(void* _pParam)
{
	INT _PckIdx = (INT)_pParam;
	if (_PckIdx >= 0 && _PckIdx < 10) {
		string _PckFile = g_PckFileDir + "\\" + string(3-AllToStr(_PckIdx).size(),'0')+AllToStr(_PckIdx)+".pck";
		vector<FileElem>& _FileList = g_PckArchData[_PckIdx];
		INT _Len = _FileList.size();
		for (INT _Idx = _Len-1; _Idx >= 0; --_Idx) {
			FileElem& _Fe = _FileList[_Idx];
			MkDir(g_ResBaseDir+"\\"+_Fe.Name,true);
			Extractor(_Fe,_PckFile);
		}
	}
	return 0;
}

void ExtractorLog(string _IdxFileBuff) 
{
	map<string,FileElem>::iterator _Iter;
	BOOL _NoPckIdx = g_NoPckIdx;
	g_NoPckIdx = FALSE;
	MakeIdxMapByIdxBuff(_IdxFileBuff,g_IdxMap);
	ZCmnFile _Log;
	_Log.OpenFile(g_ResBaseDir+"\\log.txt",true,true);
	for (_Iter = g_IdxMap.begin(); _Iter != g_IdxMap.end(); ++_Iter) {
		FileElem& _Fe = _Iter->second;
		INT _PckIdx = GetPckIdxByName(_Fe.Name);
		_Log.Text(_Fe.Name + 
			", Size: " + AllToStr(_Fe.FileLen) + 
			", CRC: " + AllToStr(_Fe.CRC,true) + 
			", PCKIdx: " + AllToStr(_Fe.ArchIdx) + 
			", RealPCKIdx: " + AllToStr(_PckIdx) + 
			", PCKIdxPct: " + AllToStr((bool)(_PckIdx!=_Fe.ArchIdx)) + 
			", Offset: " + AllToStr(_Fe.Offset));
	}
	g_NoPckIdx = _NoPckIdx;
}

BOOL ExtractorDir(const string& _IdxFileName, const string& _PckFileDir, const string& _ResBaseDir)
{
	g_PckFileDir = _PckFileDir;
	g_ResBaseDir = _ResBaseDir;
	ClearPckArchData();
	MkDir(g_ResBaseDir);
	string _IdxFileBuff = UnZipIdexFileBuff(_IdxFileName);
	ExtractorLog(_IdxFileBuff);
	MakeIdxMapByIdxBuff(_IdxFileBuff,g_IdxMap);
	map<string,FileElem>::iterator _Iter;
	for (_Iter = g_IdxMap.begin(); _Iter != g_IdxMap.end(); ++_Iter) {
		FileElem& _Fe = _Iter->second;
		g_PckArchData[_Fe.ArchIdx].push_back(_Fe);
	}
	HANDLE _UnPckArchThrd[10];
	for (INT _Idx = 0; _Idx < 10; _Idx++) {
		unsigned _ThreadID;
		_UnPckArchThrd[_Idx] = (HANDLE)_beginthreadex(NULL,NULL,UnPckArchThread,(void*)_Idx,NULL,&_ThreadID);
	}
	WaitForMultipleObjects(10,_UnPckArchThrd,TRUE,INFINITE);
	for (INT _Idx = 0; _Idx < 10; _Idx++) {
		CloseHandle(_UnPckArchThrd[_Idx]);
	}
	return TRUE;
}

BOOL Extractor(FileElem& _Fe,const string& _PckFile)
{
	ZCmnFile _File;
	if (!_File.OpenFile(_PckFile)) {
		return FALSE;
	}
	string _FileElemBuff;
	_FileElemBuff.resize(_Fe.FileLen,0);
	_File.ZFileSeek(_Fe.Offset,FILE_BEGIN);
	if (!_File.ReadFile((LPVOID)_FileElemBuff.c_str(),_Fe.FileLen)) {
		return FALSE;
	}
	if (!_File.OpenFile(g_ResBaseDir+"\\"+_Fe.Name,true)) {
		return FALSE;
	}
	_File.WriteFile((LPVOID)_FileElemBuff.c_str(),_Fe.FileLen);
	return TRUE;
}

void ArchiveLog() 
{
	map<string,FileElem>::iterator _Iter;
	ZCmnFile _Log;
	_Log.OpenFile(g_PckFileDir+"\\log.txt",true,true);
	for (_Iter = g_IdxMap.begin(); _Iter != g_IdxMap.end(); ++_Iter) {
		FileElem& _Fe = _Iter->second;
		INT _PckIdx = GetPckIdxByName(_Fe.Name);
		_Log.Text(_Fe.Name + 
			", Size: " + AllToStr(_Fe.FileLen) + 
			", CRC: " + AllToStr(_Fe.CRC,true) + 
			", PCKIdx: " + AllToStr(_Fe.ArchIdx) + 
			", RealPCKIdx: " + AllToStr(_PckIdx) + 
			", PCKIdxPct: " + AllToStr((bool)(_PckIdx!=_Fe.ArchIdx)) + 
			", Offset: " + AllToStr(_Fe.Offset));
	}
}

BOOL ArchiveDir(const string& _IdxFileName,const string& _PckFileDir, const string& _ResBaseDir)
{
	g_PckFileDir = _PckFileDir;
	g_ResBaseDir = _ResBaseDir;
	ClearPckArchData();
	string _IdxFileBuff = UnZipIdexFileBuff(_IdxFileName);
	MakeIdxMapByIdxBuff(_IdxFileBuff,g_IdxMap);
	vector<string> _FileList;
	FindAllFile(g_ResBaseDir,"",_FileList);
	if (_FileList.empty()) {
		return FALSE;
	}
	INT _Len = _FileList.size();
	for (INT _Idx = 0; _Idx < _Len; _Idx++) {
		FileElem _Fe;
		_Fe.Name = _FileList[_Idx];
		trans_tolower(_Fe.Name);
		_Fe.ArchIdx = GetPckIdxByName(_Fe.Name);
		_Fe.NameLen = _Fe.Name.size();
		g_PckArchData[_Fe.ArchIdx].push_back(_Fe);
	}
	HANDLE _PckArchThrd[10];
	for (INT _Idx = 0; _Idx < 10; _Idx++) {
		unsigned _ThreadID;
		_PckArchThrd[_Idx] = (HANDLE)_beginthreadex(NULL,NULL,PckArchThread,(void*)_Idx,NULL,&_ThreadID);
	}
	WaitForMultipleObjects(10,_PckArchThrd,TRUE,INFINITE);
	for (INT _Idx = 0; _Idx < 10; _Idx++) {
		CloseHandle(_PckArchThrd[_Idx]);
	}
	for (INT _PckIdx = 0; _PckIdx < 10; _PckIdx++) {
		vector<FileElem>& _FileList = g_PckArchData[_PckIdx];
		INT _Len = _FileList.size();
		for (INT _Idx = 0; _Idx < _Len; _Idx++) {
			FileElem& _Fe = _FileList[_Idx];
			g_IdxMap[_Fe.Name] = _Fe;
		}
	}
	MakeIdxBuffByIdxMap(_IdxFileBuff, g_IdxMap);
	ZipIdexFileBuff(_IdxFileName,_IdxFileBuff);
	ArchiveLog();
	return TRUE;
}

BOOL Archive(FileElem& _Fe,const string& _PckFile)
{
	ZCmnFile _File;
	if (!_File.OpenFile(g_ResBaseDir+"\\"+_Fe.Name)) {
		return FALSE;
	}
	_Fe.FileLen = (int)_File.ZFileGetSize();
	string _FileBuff;
	_FileBuff.resize(_Fe.FileLen);
	if (!_File.ReadFile((LPVOID)_FileBuff.c_str(),_Fe.FileLen)) {
		return FALSE;
	}
	_Fe.CRC = HashFileInPck((BYTE*)_FileBuff.c_str(),_Fe.FileLen);
	if (!_File.OpenFile(_PckFile,true)) {
		return FALSE;
	}
	_Fe.Offset = _File.ZFileGetSize();
	_File.ZFileSeek(0,FILE_END);
	_File.WriteFile((LPVOID)_FileBuff.c_str(),_FileBuff.size());
	return TRUE;
}